﻿using System;
using System.Collections.Generic;
using System.Text;

namespace ReducaoPena {
	public class TarefaCollection : List<Tarefa> {


		private readonly DiaSemana[] dias = { DiaSemana.Seg, DiaSemana.Ter, DiaSemana.Qua, DiaSemana.Qui, DiaSemana.Sex };

		public TarefaCollection() {

		}
		//=================================================================================================================


		public void GetBestPontuation(out List<Int32> pontosDiarios, out Int32 totalPontos) {
			
			Int32 maxPont = 0;
			pontosDiarios = new List<Int32>(5);
			totalPontos = 0;

			foreach (DiaSemana currentDay in dias) {

				SearchByDay s = new SearchByDay(currentDay);
				List<Tarefa> list = this.FindAll(s.Find);
				maxPont = 0;
				
				for (int i = 0; i < list.Count; i++) {

					if (i == 0) {
						foreach (Tarefa t in list) {
							if (t.Pontos > maxPont)
								maxPont = t.Pontos;
						}
					} else if (i == 1) {
						Combinacoes<Tarefa> comb = new Combinacoes<Tarefa>(list.ToArray(), i + 1);
						comb.Calcular(0, (list.Count - (i + 1)), 0);

						foreach (Tarefa[] item in comb.Resultados) {
							int soma = item[0].Pontos + item[1].Pontos;
							if (soma > maxPont) {
								//verifica conflitos
								if (!(((item[0].HoraInicio > item[1].HoraInicio & item[0].HoraInicio < item[1].HoraFim) || (item[0].HoraFim > item[1].HoraInicio & item[0].HoraFim < item[1].HoraFim)) || ((item[1].HoraInicio > item[0].HoraInicio & item[1].HoraInicio < item[0].HoraFim) || (item[1].HoraFim > item[0].HoraInicio & item[1].HoraFim < item[0].HoraFim)) || (item[1].HoraInicio == item[0].HoraInicio & item[1].HoraFim == item[0].HoraFim))) {
									maxPont = soma;
								}
							}
						}
					} else {
						Combinacoes<Tarefa> comb = new Combinacoes<Tarefa>(list.ToArray(), i + 1);
						comb.Calcular(0, (list.Count - (i + 1)), 0);

						foreach (Tarefa[] item in comb.Resultados) {
							int soma = 0;
							for (int j = 0; j < item.Length; j++)
								soma += item[j].Pontos;


							if (soma > maxPont) {
								//verifica conflitos
								Combinacoes<Tarefa> combAux = new Combinacoes<Tarefa>(item, 2);
								combAux.Calcular(0, item.Length - 2, 0);
								bool conflito = false;

								foreach (Tarefa[] itemAux in combAux.Resultados) {
									if ((((itemAux[0].HoraInicio > itemAux[1].HoraInicio & itemAux[0].HoraInicio < itemAux[1].HoraFim) || (itemAux[0].HoraFim > itemAux[1].HoraInicio & itemAux[0].HoraFim < itemAux[1].HoraFim)) || ((itemAux[1].HoraInicio > itemAux[0].HoraInicio & itemAux[1].HoraInicio < itemAux[0].HoraFim) || (itemAux[1].HoraFim > itemAux[0].HoraInicio & itemAux[1].HoraFim < itemAux[0].HoraFim)) || (itemAux[1].HoraInicio == itemAux[0].HoraInicio & itemAux[1].HoraFim == itemAux[0].HoraFim))) {
										conflito = true;
										break;
									}
								}

								if (!conflito)
									maxPont = soma;
							}
						}
					}
				}

				pontosDiarios.Add(maxPont);
				totalPontos += maxPont;
			}
		}



		//=================================================================================================================
		private class SearchByDay {

			private DiaSemana day;

			public SearchByDay(DiaSemana day) {
				this.day = day;
			}

			public bool Find(Tarefa t) {

				if (t.Dia == this.day)
					return true;
				else
					return false;
			}
		}

		//=================================================================================================================
		private class Combinacoes<T> where T : ICloneable {

			private int quantidade;
			private T[] itens;
			private T[] resultado;
			private List<T[]> resultados;

			public List<T[]> Resultados {
				get { return this.resultados; }
			}

			public void Calcular(int inicio, int fim, int profundidade) {

				if ((profundidade + 1) >= this.quantidade)
					for (int x = inicio; x <= fim; x++) {
						this.resultado[profundidade] = (T)this.itens[x].Clone();
						this.resultados.Add((T[])this.resultado.Clone());
					} else
					for (int x = inicio; x <= fim; x++) {
						this.resultado[profundidade] = (T)this.itens[x].Clone();
						this.Calcular(x + 1, fim + 1, profundidade + 1);
					}
			}

			public Combinacoes(T[] itens, int quantidade) {
				this.quantidade = quantidade;
				this.resultado = new T[quantidade];
				this.itens = itens;
				this.resultados = new List<T[]>();
			}
		}
	}




}
